package mapper

import (
	"bytes"
	"fmt"
	"github.com/zeromicro/go-zero/core/logx"
	"go-zero-project/services/user/rpc/internal/mapper/bo"
	"go-zero-project/services/user/rpc/internal/mapper/entity"
	"gorm.io/gorm"
)

const menuSqlColumn = "menu_id,parent_id,name,url,perms,icon,type,order_num"

type MenuMapper struct {
}

func NewMenuMapper() *MenuMapper {
	return &MenuMapper{}
}

func (m *MenuMapper) QueryListParentId(db *gorm.DB, parentId int64) ([]entity.SysMenuEntity, error) {
	//select * from sys_menu where parent_id = #{parentId} order by order_num asc
	tx := db.Session(&gorm.Session{SkipDefaultTransaction: true})
	var sysMenu []entity.SysMenuEntity
	tx = tx.Select(menuSqlColumn).Where("parent_id", parentId).Find(&sysMenu)
	return sysMenu, tx.Error
}

func (m *MenuMapper) SelectCount(db *gorm.DB, bo bo.SysMenuBO) (int64, error) {
	tx := db.Session(&gorm.Session{SkipDefaultTransaction: true})
	whereSql := m.getAllWhereSql(bo)
	var total int64
	userEntity := entity.SysMenuEntity{}
	tx = tx.Select(menuSqlColumn).Table(userEntity.TableName()).
		Where(whereSql.String()).Count(&total)
	return total, tx.Error
}

func (m *MenuMapper) SelectOne(db *gorm.DB, bo bo.SysMenuBO) (entity.SysMenuEntity, error) {
	tx := db.Session(&gorm.Session{SkipDefaultTransaction: true})
	whereSql := m.getAllWhereSql(bo)
	var user entity.SysMenuEntity
	logx.Infof(whereSql.String())
	tx = tx.Select(menuSqlColumn).Where(whereSql.String()).First(&user)
	return user, tx.Error
}

func (m *MenuMapper) SelectList(db *gorm.DB, bo bo.SysMenuBO) ([]entity.SysMenuEntity, error) {
	tx := db.Session(&gorm.Session{SkipDefaultTransaction: true})
	whereSql := m.getAllWhereSql(bo)
	whereSql.WriteString(" order by order_num desc")
	var retList []entity.SysMenuEntity
	if bo.PageSize > 0 {
		// 查询语句
		tx = tx.Select(menuSqlColumn).Where(whereSql.String()).Offset(bo.StartIndex).Limit(bo.PageSize).Find(&retList)
	} else {
		// 查询语句
		tx = tx.Select(menuSqlColumn).Where(whereSql.String()).Find(&retList)
	}
	return retList, tx.Error
}

func (m *MenuMapper) getAllWhereSql(menuBO bo.SysMenuBO) bytes.Buffer {
	var whereSql bytes.Buffer
	whereSql.WriteString(defaultWhere)
	if menuBO.MenuId > 0 {
		whereSql.WriteString(fmt.Sprintf(" and menu_id =%d", menuBO.MenuId))
	}
	if !menuBO.NoParentId {
		whereSql.WriteString(fmt.Sprintf(" and parent_id =%d", menuBO.ParentId))
	}
	if len(menuBO.Name) > 0 || menuBO.Name != "" {
		whereSql.WriteString(fmt.Sprintf(" and name ='%s'", menuBO.Name))
	}
	if len(menuBO.NameLike) > 0 || menuBO.NameLike != "" {
		whereSql.WriteString(fmt.Sprintf(" role_name  like concat ('%s','%s','%s')",
			"%", menuBO.NameLike, "%"))
	}
	if len(menuBO.Url) > 0 || menuBO.Url != "" {
		whereSql.WriteString(fmt.Sprintf(" and url ='%s'", menuBO.Url))
	}
	if len(menuBO.UrlLike) > 0 || menuBO.UrlLike != "" {
		whereSql.WriteString(fmt.Sprintf(" url  like concat ('%s','%s','%s')",
			"%", menuBO.UrlLike, "%"))
	}
	if len(menuBO.Perms) > 0 || menuBO.Perms != "" {
		whereSql.WriteString(fmt.Sprintf(" and perms ='%s'", menuBO.Perms))
	}
	if len(menuBO.PermsLike) > 0 || menuBO.PermsLike != "" {
		whereSql.WriteString(fmt.Sprintf(" url  like concat ('%s','%s','%s')",
			"%", menuBO.PermsLike, "%"))
	}
	if !menuBO.NoType {
		whereSql.WriteString(fmt.Sprintf(" and type ='%d'", menuBO.Type))
	}
	if len(menuBO.Icon) > 0 || menuBO.Icon != "" {
		whereSql.WriteString(fmt.Sprintf(" and icon ='%s'", menuBO.Icon))
	}
	if menuBO.OrderNum > 0 {
		whereSql.WriteString(fmt.Sprintf(" and order_num =%d", menuBO.OrderNum))
	}
	return whereSql
}

func (m *MenuMapper) QueryNotButtonList(db *gorm.DB) ([]entity.SysMenuEntity, error) {
	//select * from sys_menu where type != 2 order by order_num asc
	tx := db.Session(&gorm.Session{SkipDefaultTransaction: true})
	//whereSql.WriteString(" order by order_num desc")
	var retList []entity.SysMenuEntity
	tx = tx.Select(menuSqlColumn).Where(" type != 2").
		Order("order_num desc").Find(&retList)
	return retList, tx.Error
}

func (m *MenuMapper) SaveMenu(db *gorm.DB, entity *entity.SysMenuEntity) error {
	tx := db.Create(entity)
	return tx.Error
}

// UpdateMenuByMenuId UpdateMenu 使用 map 更新多个属性，只会更新其中有变化的属性 通过 struct 更新多个属性，只会更新其中有变化且为非零值的字段
func (m *MenuMapper) UpdateMenuByMenuId(db *gorm.DB, menuEntity entity.SysMenuEntity) error {
	// 这里修改存在问题 对于0 UpdateColumn
	tx := db.Model(&menuEntity).Where("menu_id", menuEntity.MenuId).UpdateColumns(menuEntity)
	return tx.Error
}

func (m *MenuMapper) DeleteByMenuId(db *gorm.DB, id int64) error {
	//tx := db.Where("menu_id", id).Delete(&entity.SysMenuEntity{})
	delSql := "delete from sys_menu where menu_id=?"
	tx := db.Exec(delSql, id)
	return tx.Error
}
